﻿using System;
using System.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Workflow;
using System.Data;
using System.Reflection;
using System.Web.UI.WebControls;

namespace AdminPack.Layouts.AdminPack.WorkflowOrganizer
{
    public partial class settings : LayoutsPageBase
    {
        protected Label lblError;
        protected Button btnOK;
        protected DropDownList ddlWorkflows;
        protected DropDownList ddlEvents;
        protected DropDownList ddlDelay;
        protected Button btnSave;
        public Guid ListId = new Guid();
        public SPGridView gvEvents;

        string assembly = Assembly.GetExecutingAssembly().FullName;
        string className = "AdminPack.WorkflowOrganizerReceiver.WorkflowOrganizerReceiver";

        /// <summary>
        /// Load up all of the data
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (Request.QueryString["List"] != "")
                ListId = new Guid(Request.QueryString["List"].ToString());
            else
                Response.Redirect(SPContext.Current.Web.Url);

            if (!IsPostBack)
            {
                LoadWorkflows();
                LoadEvents();
                LoadExisting();
            }

        }

        /// <summary>
        /// Load the event types for the current list
        /// </summary>
        private void LoadEvents()
        {
            try
            {
                ddlEvents.Items.AddRange(GetAllItemEvents());
            }
            catch (Exception ex)
            {
                lblError.Text = ex.ToString();
            }
        }

        /// <summary>
        /// Load the workflows associated with this list
        /// </summary>
        private void LoadWorkflows()
        {
            try
            {
                using (SPSite site = new SPSite(SPContext.Current.Site.ID))
                {
                    using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
                    {
                        SPList list = web.Lists[ListId];
                        ddlWorkflows.Items.AddRange(GetWorkflows(list.WorkflowAssociations));
                    }
                }
            }
            catch (Exception ex)
            {
                lblError.Text = ex.ToString();
            }
        }

        /// <summary>
        /// Returns an array of event types
        /// </summary>
        /// <returns></returns>
        ListItem[] GetAllItemEvents()
        {
            try
            {
                var items = from string type in Enum.GetNames(typeof(SPEventReceiverType))
                            where type.Contains("Item")
                            orderby type
                            select new ListItem(type);

                return items.ToArray();
            }
            catch (Exception ex)
            {
                lblError.Text = ex.ToString();
                return null;
            }
        }

        /// <summary>
        /// Returns an array of associated workflows
        /// </summary>
        /// <param name="workflows"></param>
        /// <returns></returns>
        ListItem[] GetWorkflows(SPWorkflowAssociationCollection workflows)
        {

            try
            {
                var items = from SPWorkflowAssociation workflow in workflows
                            orderby workflow.Name
                            select new ListItem(workflow.Name, workflow.Id.ToString());

                return items.ToArray();
            }
            catch (Exception ex)
            {
                lblError.Text = ex.ToString();
                return null;
            }
        }

        /// <summary>
        /// Simply redirects user to workflow settings page
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnOK_Click(object sender, EventArgs e)
        {
            Response.Redirect(SPContext.Current.Web.Url + "/_layouts/WrkSetng.aspx?List=" + Server.UrlEncode(ListId.ToString()));
        }

        /// <summary>
        /// Saves the settings
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void btnSave_Click(object sender, EventArgs e)
        {
            try
            {
                using (SPSite site = new SPSite(SPContext.Current.Site.ID))
                {
                    using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
                    {
                        SPList list = web.Lists[ListId];

                        //add the event receiver
                        list.EventReceivers.Add((SPEventReceiverType)Enum.Parse(typeof(SPEventReceiverType), ddlEvents.SelectedValue), assembly, className);
                        
                        //store the settings in the currnet list root folder property collection
                        if (list.RootFolder.Properties["WorkflowOrder"] != null)
                            list.RootFolder.Properties["WorkflowOrder"] += "^" + ddlEvents.SelectedValue + "|" + ddlWorkflows.SelectedValue + "|" + ddlDelay.SelectedValue;
                        else
                            list.RootFolder.Properties["WorkflowOrder"] = ddlEvents.SelectedValue + "|" + ddlWorkflows.SelectedValue + "|" + ddlDelay.SelectedValue;

                        list.RootFolder.Update();

                        //disable the workflow from starting, it'll be handled in the event receiver.
                        SPWorkflowAssociation assoc = list.WorkflowAssociations[new Guid(ddlWorkflows.SelectedValue)];
                        assoc.AutoStartChange = false;
                        assoc.AutoStartCreate = false;
                        assoc.AllowManual = true;
                        assoc.AllowAsyncManualStart = true;
                        list.UpdateWorkflowAssociation(assoc);

                        ddlWorkflows.SelectedIndex = 0;
                        ddlEvents.SelectedIndex = 0;
                        LoadExisting();
                    }
                }
            }
            catch (Exception ex)
            {
                lblError.Text = ex.ToString();
            }
        }

        /// <summary>
        /// Load any existing settings
        /// </summary>
        private void LoadExisting()
        {
            try
            {
                using (SPSite site = new SPSite(SPContext.Current.Site.ID))
                {
                    using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
                    {
                        SPList list = web.Lists[ListId];

                        DataSet ds = CreateFieldDataSet();

                        string existing = "";

                        if (list.RootFolder.Properties["WorkflowOrder"] != null)
                            existing = list.RootFolder.Properties["WorkflowOrder"].ToString();


                        if (existing != "")
                        {
                            Boolean makeUpdate = false;
                            string[] sets = existing.Split('^');

                            int cnt = 0;

                            foreach (string s in sets)
                            {
                                if (s.Contains("|"))
                                {
                                    string[] items = s.Split('|');
                                    string eventName = items[0];
                                    string workflowId = items[1];
                                    int delay = 0;
                                    int.TryParse(items[2], out delay);

                                    SPWorkflowAssociation assoc = list.WorkflowAssociations[new Guid(workflowId)];
                                    if (assoc != null)
                                    {
                                        DataRow ndr = ds.Tables[0].NewRow();
                                        ndr["ID"] = cnt;
                                        ndr["Workflow"] = assoc.Name;
                                        ndr["Event"] = eventName;
                                        ndr["Delay"] = delay;
                                        ds.Tables[0].Rows.Add(ndr);
                                    }
                                    else
                                    {
                                        //the workflow was removed from the list so remove it from our settings
                                        existing = existing.Replace(s, "");
                                        makeUpdate = true;
                                    }
                                }
                                cnt++;
                            }
                            if (makeUpdate)
                            {
                                if (existing.Contains("^^"))
                                    existing = existing.Replace("^^", "^");

                                web.AllowUnsafeUpdates = true;
                                list.RootFolder.Properties["WorkflowOrder"] = existing;
                                list.RootFolder.Update();

                            }
                        }

                        gvEvents.DataSource = ds;
                        gvEvents.DataBind();

                        if (ds.Tables[0].Rows.Count > 0)
                        {
                            ((LinkButton)gvEvents.Rows[0].FindControl("lnkBtnUp")).Visible = false;
                            ((LinkButton)gvEvents.Rows[ds.Tables[0].Rows.Count - 1].FindControl("lnkBtnDown")).Visible = false;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                lblError.Text = ex.ToString();
            }
        }


        DataSet CreateFieldDataSet()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add(new DataColumn("ID", System.Type.GetType("System.Int32")));
            dt.Columns.Add(new DataColumn("Workflow"));
            dt.Columns.Add(new DataColumn("Event"));
            dt.Columns.Add(new DataColumn("Delay", System.Type.GetType("System.Int32")));
            DataSet ds = new DataSet();
            ds.Tables.Add(dt);
            return ds;
        }


        protected void gvEvents_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            try
            {
                using (SPSite site = new SPSite(SPContext.Current.Site.ID))
                {
                    int intParam = Convert.ToInt32(e.CommandArgument);
                    string existing = "";

                    using (SPWeb web = site.OpenWeb(SPContext.Current.Web.ID))
                    {
                        SPList list = web.Lists[ListId];

                        if (list.RootFolder.Properties["WorkflowOrder"] != null)
                            existing = list.RootFolder.Properties["WorkflowOrder"].ToString();


                        if (existing != "")
                        {
                            string[] sets = existing.Split('^');

                            if (e.CommandName == "delete")
                            {

                                existing = existing.Replace(sets[intParam], "");

                                if (existing.Contains("^^"))
                                    existing = existing.Replace("^^", "^");

                                list.RootFolder.Properties["WorkflowOrder"] = existing;
                                list.RootFolder.Update();

                                //TODO:check for last ItemEvent and remove the association if no more remain
                                Response.Redirect(web.Url + "/_layouts/AdminPack/WorkflowOrganizer/settings.aspx?List=" + Request.QueryString["List"].ToString());
                            }
                            if (e.CommandName == "up")
                            {
                                string tomove = sets[intParam];
                                int newid = intParam - 1;
                                existing = existing.Replace(sets[intParam], "");
                                sets = existing.Split('^');

                                string newset = "";

                                for (int i = 0; i < sets.Count(); i++)
                                {
                                    if (i == newid)
                                    {
                                        newset += "^" + tomove;
                                        newset += "^" + sets[i];
                                        i++;
                                    }
                                    else
                                    {
                                        newset += "^" + sets[i];
                                    }
                                }
                                newset = newset.Replace("^^", "^");
                                list.RootFolder.Properties["WorkflowOrder"] = newset;
                                list.RootFolder.Update();

                                LoadExisting();

                            }
                            if (e.CommandName == "down")
                            {
                                string tomove = sets[intParam];
                                int newid = intParam + 1;
                                existing = existing.Replace(sets[intParam], "");
                                sets = existing.Split('^');

                                string newset = "";

                                for (int i = 0; i < sets.Count(); i++)
                                {
                                    if (i == newid)
                                    {
                                        newset += "^" + sets[i];
                                        newset += "^" + tomove;
                                        i++;
                                    }
                                    else
                                    {
                                        newset += "^" + sets[i];
                                    }
                                }
                                newset = newset.Replace("^^", "^");
                                list.RootFolder.Properties["WorkflowOrder"] = newset;
                                list.RootFolder.Update();

                                LoadExisting();

                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                lblError.Text = ex.ToString();
            }
        }
    }
}
